Crate mirror_mirror
source ·Expand description
General purpose reflection library for Rust.
§Examples
§Access a field by its string name and mutate it
use mirror_mirror::{Reflect, Struct};
#[derive(Reflect, Clone, Debug)]
struct Foo {
x: i32,
}
let mut foo = Foo { x: 42 };
// Get a `Struct` trait object for `Foo`.
//
// The `Struct` trait has methods available for all structs such as accessing
// fields by name and iterating over the fields.
let struct_obj: &mut dyn Struct = foo.as_struct_mut()?;
// Mutably borrow the `x` field. We can access fields using string names.
let x: &mut dyn Reflect = struct_obj.field_mut("x")?;
// Downcast `x` into a mutable `i32`
let x: &mut i32 = x.downcast_mut::<i32>()?;
// Change the value of `x`
*x += 1;
// The value of `x` in `foo` has now changed.
assert_eq!(foo.x, 43);
§Iterate over all fields
use mirror_mirror::{Reflect, Struct, ReflectMut, ScalarMut, enum_::VariantFieldMut};
// A function that iterates over the fields in an enum and mutates them.
fn change_enum_fields(value: &mut dyn Reflect) -> Option<()> {
let enum_ = value.as_enum_mut()?;
for field in enum_.fields_mut() {
match field {
VariantFieldMut::Struct(_, value) | VariantFieldMut::Tuple(value) => {
match value.reflect_mut() {
ReflectMut::Scalar(ScalarMut::i32(n)) => {
*n *= 2;
}
ReflectMut::Scalar(ScalarMut::String(s)) => {
*s = format!("{s}bar");
}
// Ignore other types
_ => {}
}
}
}
}
Some(())
}
#[derive(Reflect, Clone, Debug)]
enum Bar {
X { x: i32 },
Y(String),
}
let mut bar = Bar::X { x: 42 };
change_enum_fields(bar.as_reflect_mut())?;
assert!(matches!(bar, Bar::X { x: 84 }));
let mut bar = Bar::Y("foo".to_owned());
change_enum_fields(bar.as_reflect_mut())?;
assert!(matches!(bar, Bar::Y(s) if s == "foobar"));
§Query value and type information using key paths
use mirror_mirror::{
Reflect,
key_path,
key_path::{GetPath, GetTypePath, field},
type_info::{DescribeType, ScalarType},
};
// Some complex nested data type.
#[derive(Reflect, Clone, Debug)]
struct User {
employer: Option<Company>,
}
#[derive(Reflect, Clone, Debug)]
struct Company {
countries: Vec<Country>,
}
#[derive(Reflect, Clone, Debug)]
struct Country {
name: String
}
let user = User {
employer: Some(Company {
countries: vec![Country {
name: "Denmark".to_owned(),
}],
}),
};
// Build a key path that represents accessing `.employer::Some.0.countries[0].name`.
//
// `::Some` means to access the `Some` variant of `Option<Company>`.
let path = field("employer").variant("Some").field(0).field("countries").get(0).field("name");
// Get the value at the key path.
assert_eq!(user.get_at::<String>(&path).unwrap(), "Denmark");
// Key paths can also be constructed using the `key_path!` macro.
// This invocation expands the same code we have above.
let path = key_path!(.employer::Some.0.countries[0].name);
// Use the same key path to query type information. You don't need a value
// of the type to access its type information.
let user_type = <User as DescribeType>::type_descriptor();
assert!(matches!(
user_type.type_at(&path).unwrap().as_scalar().unwrap(),
ScalarType::String,
));
§Using opaque Value
types
use mirror_mirror::{Reflect, Value, FromReflect};
#[derive(Reflect, Clone, Debug)]
struct Foo(Vec<i32>);
let foo = Foo(vec![1, 2, 3]);
// Convert `foo` into general "value" type.
let mut value: Value = foo.to_value();
// `Value` also implements `Reflect` so it can be mutated in the
// same way we've seen before. So these mutations can be made
// by another crate that doesn't know about the `Foo` type.
//
// `Value` is also serializable with `speedy`, for binary serialization,
// or `serde`, for everything else.
value
.as_tuple_struct_mut()?
.field_at_mut(0)?
.as_list_mut()?
.push(&4);
// Convert the `value` back into a `Foo`.
let new_foo = Foo::from_reflect(&value)?;
// Our changes were applied.
assert_eq!(new_foo.0, vec![1, 2, 3, 4]);
§Inspiration
The design of this library is heavily inspired by bevy_reflect
but with a few key
differences:
speedy
integration which is useful for marshalling data perhaps to send it across FFI.- A
Value
type that can be serialized and deserialized without using trait objects. - More type information captured.
- Add meta data to types which becomes part of the type information.
- Key paths for querying value and type information.
- No dependencies on
bevy
specific crates. #![no_std]
support.
§Feature flags
mirror-mirror uses a set of [feature flags] to optionally reduce the number of dependencies.
The following optional features are available:
Modules§
- Reflected array types.
- Reflected enum types.
- Helper traits for accessing fields on reflected values.
- Iterator types.
- Key paths for querying value and type information.
- Reflected list types.
- Reflected map types.
- Reflected struct types.
- Reflected tuple types.
- Reflected tuple struct types.
- Type information.
- Type erased value types.
Macros§
- Convenience macro for creating
KeyPath
s.
Structs§
- The root of a type.
Enums§
- A mutable reflected value.
- An owned reflected value.
- An immutable reflected value.
- An mutable reflected scalar value.
- An owned reflected scalar type.
- An immutable reflected scalar value.
- A type erased value type.
Traits§
- A reflected array type.
- Trait for accessing type information.
- A reflected enum type.
- A trait for types which can be constructed from a reflected type.
- Helper trait for accessing and downcasting fields on reflected values.
- Helper trait for mutably accessing and downcasting fields on reflected values.
- A reflected list type.
- A reflected map type.
- A reflected type.
- A reflected struct type.
- A reflected tuple type.
- A reflected tuple struct type.
Functions§
- Debug formatter for any reflection value.
- Compare two reflected values for equality.
Derive Macros§
- Derive an implementation of
Reflect
and other appropriate traits.